﻿using System;
using System.Collections.Generic;
using GeoAPI.Geometries;
using YJKGridTopologyCal.Operation.Overlay.Snap;

namespace YJKGridTopologyCal.Operation.Overlay.Validate
{
	public class OverlayResultValidator
	{
		public static bool IsValid(IGeometry a, IGeometry b, SpatialFunction overlayOp, IGeometry result)
		{
			return new OverlayResultValidator(a, b, result).IsValid(overlayOp);
		}

		private static double ComputeBoundaryDistanceTolerance(IGeometry g0, IGeometry g1)
		{
			return Math.Min(GeometrySnapper.ComputeSizeBasedSnapTolerance(g0), GeometrySnapper.ComputeSizeBasedSnapTolerance(g1));
		}

		public OverlayResultValidator(IGeometry a, IGeometry b, IGeometry result)
		{
			this._boundaryDistanceTolerance = OverlayResultValidator.ComputeBoundaryDistanceTolerance(a, b);
			this._geom = new IGeometry[]
			{
				a,
				b,
				result
			};
			this._locFinder = new FuzzyPointLocator[]
			{
				new FuzzyPointLocator(this._geom[0], this._boundaryDistanceTolerance),
				new FuzzyPointLocator(this._geom[1], this._boundaryDistanceTolerance),
				new FuzzyPointLocator(this._geom[2], this._boundaryDistanceTolerance)
			};
		}

		public bool IsValid(SpatialFunction overlayOp)
		{
			this.AddTestPts(this._geom[0]);
			this.AddTestPts(this._geom[1]);
			return this.CheckValid(overlayOp);
		}

		public Coordinate InvalidLocation
		{
			get
			{
				return this._invalidLocation;
			}
		}

		private void AddTestPts(IGeometry g)
		{
			OffsetPointGenerator offsetPointGenerator = new OffsetPointGenerator(g);
			this._testCoords.AddRange(offsetPointGenerator.GetPoints(5.0 * this._boundaryDistanceTolerance));
		}

		private bool CheckValid(SpatialFunction overlayOp)
		{
			for (int i = 0; i < this._testCoords.Count; i++)
			{
				Coordinate coordinate = this._testCoords[i];
				if (!this.CheckValid(overlayOp, coordinate))
				{
					this._invalidLocation = coordinate;
					return false;
				}
			}
			return true;
		}

		private bool CheckValid(SpatialFunction overlayOp, Coordinate pt)
		{
			this._location[0] = this._locFinder[0].GetLocation(pt);
			this._location[1] = this._locFinder[1].GetLocation(pt);
			this._location[2] = this._locFinder[2].GetLocation(pt);
			return OverlayResultValidator.HasLocation(this._location, Location.Boundary) || OverlayResultValidator.IsValidResult(overlayOp, this._location);
		}

		private static bool HasLocation(Location[] location, Location loc)
		{
			for (int i = 0; i < 3; i++)
			{
				if (location[i] == loc)
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsValidResult(SpatialFunction overlayOp, Location[] location)
		{
			bool flag = OverlayOp.IsResultOfOp(location[0], location[1], overlayOp);
			bool flag2 = location[2] == Location.Interior;
			bool flag3 = flag == flag2;
			if (!flag3)
			{
				OverlayResultValidator.ReportResult(overlayOp, location, flag);
			}
			return flag3;
		}

		private static void ReportResult(SpatialFunction overlayOp, Location[] location, bool expectedInterior)
		{
		}

		private const double Tolerance = 1E-06;

		private readonly IGeometry[] _geom;

		private readonly FuzzyPointLocator[] _locFinder;

		private readonly Location[] _location = new Location[3];

		private readonly double _boundaryDistanceTolerance = 1E-06;

		private readonly List<Coordinate> _testCoords = new List<Coordinate>();

		private Coordinate _invalidLocation;
	}
}
